#include "Blockqueue.hpp"
#include "Task.hpp"
#include <time.h>
#include <sys/types.h>
char ops[] = {'+', '-', '*', '/', '%', '.'};

template<class T>
class ThreadData
{
public:
    ThreadData()
    {}
    ThreadData(std::string name, Blockqueue<T>* bq)
    :_name(name), _bq(bq)
    {}
public:
    std::string _name;
    Blockqueue<T>* _bq;
};

void* consumer(void *args)
{
    ThreadData<Task>* td = static_cast<ThreadData<Task>*>(args);
    while(true)
    {
        Task t;
        td->_bq->pop(t);
        t();
        std::cout << "Customer task" << t.PrintResult() << ',' << td->_name << std::endl; 
    }

    return nullptr;
}

void* producter(void *args)
{
    ThreadData<Task>* td = static_cast<ThreadData<Task>*>(args);
    while(true)
    {
        int x = rand() % 10;
        usleep(rand() % 123);
        int y = rand() % 10;
        usleep(rand() % 123);
        char op = ops[rand() % 6];
        Task t(x, y, op);
        std::cout << "Productor task" << t.PrintTask() << ',' << td->_name << std::endl;
        td->_bq->push(t);
    }
    return nullptr;
}
int main()
{
    srand(time(nullptr) ^ getpid());
    Blockqueue<Task> *bq = new Blockqueue<Task>(10);

    pthread_t c[2], p[3];

    std::string name1 = "Thread-1";
    std::string name2 = "Thread-2";
    std::string name3 = "Thread-3";
    std::string name4 = "Thread-4";
    std::string name5 = "Thread-5";

    ThreadData<Task>* td1 = new ThreadData<Task>(name1, bq);
    ThreadData<Task>* td2 = new ThreadData<Task>(name2, bq);
    ThreadData<Task>* td3 = new ThreadData<Task>(name3, bq);
    ThreadData<Task>* td4 = new ThreadData<Task>(name4, bq);
    ThreadData<Task>* td5 = new ThreadData<Task>(name5, bq);

    pthread_create(&c[0], nullptr, consumer, td1);
    pthread_create(&c[1], nullptr, consumer, td2);
    pthread_create(&p[0], nullptr, producter, td3);
    pthread_create(&p[1], nullptr, producter, td4);
    pthread_create(&p[2], nullptr, producter, td5);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);

    return 0;
}